<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>系统登录 | Turbo Cloud</title>
    <meta name="generator" content="VuePress 1.9.7">
    <link rel="icon" href="/turbo-cloud-blog/assets/img/favicon.ico">
    <meta name="description" content="Turbo Cloud 官方文档">
    <meta name="keywords" content="Turbo Cloud">
    <meta name="theme-color" content="#1890ff">
    
    <link rel="preload" href="/turbo-cloud-blog/assets/css/0.styles.381a30c5.css" as="style"><link rel="preload" href="/turbo-cloud-blog/assets/js/app.fa1a75e5.js" as="script"><link rel="preload" href="/turbo-cloud-blog/assets/js/2.5e61b679.js" as="script"><link rel="preload" href="/turbo-cloud-blog/assets/js/8.a23eef87.js" as="script"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/10.7b8376a1.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/11.602e2a63.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/12.e733c92a.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/13.0f5f7f7c.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/3.21ac3373.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/4.94346478.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/5.5a5b15d6.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/6.9d47cb7a.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/7.5a12dc76.js"><link rel="prefetch" href="/turbo-cloud-blog/assets/js/9.47d98ce3.js">
    <link rel="stylesheet" href="/turbo-cloud-blog/assets/css/0.styles.381a30c5.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/turbo-cloud-blog/" class="home-link router-link-active"><img src="/turbo-cloud-blog/assets/img/logo.svg" alt="Turbo Cloud" class="logo"> <span class="site-name can-hide">Turbo Cloud</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/turbo-cloud-blog/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="指南" class="dropdown-title"><a href="/turbo-cloud-blog/pages/24112f/" class="link-title">指南</a> <span class="title" style="display:none;">指南</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/turbo-cloud-blog/pages/24112f/" class="nav-link">快速入门</a></li></ul></div></div><div class="nav-item"><a href="/turbo-cloud-blog/pages/f84a74/" class="nav-link">问答</a></div><div class="nav-item"><a href="/turbo-cloud-blog/pages/4fedc2/" class="nav-link">💖支持</a></div><div class="nav-item"><a href="/turbo-cloud-blog/pages/4fabc2/" class="nav-link">更新日志</a></div> <a href="https://gitee.com/aquarian-bottle" target="_blank" rel="noopener noreferrer" class="repo-link">
    Gitee
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <nav class="nav-links"><div class="nav-item"><a href="/turbo-cloud-blog/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="指南" class="dropdown-title"><a href="/turbo-cloud-blog/pages/24112f/" class="link-title">指南</a> <span class="title" style="display:none;">指南</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/turbo-cloud-blog/pages/24112f/" class="nav-link">快速入门</a></li></ul></div></div><div class="nav-item"><a href="/turbo-cloud-blog/pages/f84a74/" class="nav-link">问答</a></div><div class="nav-item"><a href="/turbo-cloud-blog/pages/4fedc2/" class="nav-link">💖支持</a></div><div class="nav-item"><a href="/turbo-cloud-blog/pages/4fabc2/" class="nav-link">更新日志</a></div> <a href="https://gitee.com/aquarian-bottle" target="_blank" rel="noopener noreferrer" class="repo-link">
    Gitee
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav> <div class="sidebar-slot sidebar-slot-top">
    
  </div> <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>快速入门</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/turbo-cloud-blog/pages/24112f/" class="sidebar-link">简介</a></li><li><a href="/turbo-cloud-blog/pages/226c21/" class="sidebar-link">快速开始</a></li><li><a href="/turbo-cloud-blog/pages/bab2db/" aria-current="page" class="active sidebar-link">系统登录</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/turbo-cloud-blog/pages/bab2db/#系统登录图" class="sidebar-link">系统登录图</a></li><li class="sidebar-sub-header level2"><a href="/turbo-cloud-blog/pages/bab2db/#系统登录设计" class="sidebar-link">系统登录设计</a></li><li class="sidebar-sub-header level2"><a href="/turbo-cloud-blog/pages/bab2db/#spring-security" class="sidebar-link">Spring Security</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#springsecurity-配置" class="sidebar-link">SpringSecurity 配置</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#springsecurity-过滤器" class="sidebar-link">SpringSecurity 过滤器</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#springsecurity-异常处理自定义类" class="sidebar-link">SpringSecurity 异常处理自定义类</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#springsecurity-使用工具类" class="sidebar-link">SpringSecurity 使用工具类</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/turbo-cloud-blog/pages/bab2db/#jwt" class="sidebar-link">JWT</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#jwt的组成" class="sidebar-link">JWT的组成</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#jwt-使用" class="sidebar-link">JWT 使用</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#jwt-配置类" class="sidebar-link">JWT 配置类</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#jwt-工具类" class="sidebar-link">JWT 工具类</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/turbo-cloud-blog/pages/bab2db/#happy-captcha-图形验证码" class="sidebar-link">Happy Captcha 图形验证码</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#图形验证码接口" class="sidebar-link">图形验证码接口</a></li><li class="sidebar-sub-header level3"><a href="/turbo-cloud-blog/pages/bab2db/#用户登录验证" class="sidebar-link">用户登录验证</a></li></ul></li></ul></li><li><a href="/turbo-cloud-blog/pages/3b5af0/" class="sidebar-link">系统权限</a></li></ul></section></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="placeholder"></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">系统登录<!----></h1> <div class="page-slot page-slot-top">
    <style>
      .page-wwads{
        width:100%!important;
        min-height: 0;
        margin: 0;
      }
      .page-wwads .wwads-img img{
        width:80px!important;
      }
      .page-wwads .wwads-poweredby{
        width: 40px;
        position: absolute;
        right: 25px;
        bottom: 3px;
      }
      .wwads-content .wwads-text, .page-wwads .wwads-text{
        height: 100%;
        padding-top: 5px;
        display: block;
      }
    </style>
  </div> <div class="theme-vdoing-content content__default"><p>前后端分离的微服务架构，基于 <code>spring-boot-starter-security</code>和<code>jwt</code>实现认证和授权。</p> <ul><li>熟悉 spring-boot-starter-security</li> <li>熟悉 jwt</li> <li>熟悉 Vue3.0、Vite、 Ant-Design-Vue、TypeScript</li></ul> <h2 id="系统登录图"><a href="#系统登录图" class="header-anchor">#</a> 系统登录图</h2> <ul><li>前端基于Vue3.0、Vite、 Ant-Design-Vue、TypeScript，权限模型自主设计。</li></ul> <div class="custom-block tip"><p class="custom-block-title">提示</p> <p>请参考 Vben Admin官网文档，地址：<a href="https://doc.vvbin.cn/" target="_blank" rel="noopener noreferrer">Vben Admin<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div> <p><img src="/turbo-cloud-blog/assets/img/turbo-cloud-login.png" alt="turbo-cloud-login"></p> <h2 id="系统登录设计"><a href="#系统登录设计" class="header-anchor">#</a> 系统登录设计</h2> <ul><li>登录验证成功服务生成<code>JWT Token</code>返回给Vue前端，Vue前端发起请求需要再http请求（Request）header的<code>Authorization</code>里面携带<code>JWT Token</code>回来；<code>JWT Token</code>存在有效期验证，有效期内发送的请求临过期Token验证通过，<code>JWT Token</code>会重新生成，放回http返回（Response）header的<code>Refresh-Authorization</code>里面。</li></ul> <p><img src="/turbo-cloud-blog/assets/img/jwt-login-verified-flow.png" alt="jwt-login-verified"></p> <h2 id="spring-security"><a href="#spring-security" class="header-anchor">#</a> Spring Security</h2> <ul><li>SpringSecurity是一个强大的可高度定制的认证和授权框架，对于Spring应用来说它是一套Web安全标准。</li> <li>SpringSecurity注重于为Java应用提供认证和授权功能，像所有的Spring项目一样，它对自定义需求具有强大的扩展性。</li></ul> <div class="custom-block tip"><p class="custom-block-title">提示</p> <p>请参考 Spring官网文档，地址：<a href="https://spring.io/projects/spring-security" target="_blank" rel="noopener noreferrer">Spring Security<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-security<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h3 id="springsecurity-配置"><a href="#springsecurity-配置" class="header-anchor">#</a> SpringSecurity 配置</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * SpringSecurity的配置
 * prePostEnabled = true 的作用的是启用Spring Security的@PreAuthorize 以及@PostAuthorize 注解。
 * securedEnabled = true 的作用是启用Spring Security的@Secured 注解。
 * jsr250Enabled = true 的作用是启用@RoleAllowed 注解
 */</span>
<span class="token annotation punctuation">@Order</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@RequiredArgsConstructor</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token annotation punctuation">@EnableWebSecurity</span>
<span class="token annotation punctuation">@EnableGlobalMethodSecurity</span><span class="token punctuation">(</span>prePostEnabled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> securedEnabled <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebSecurityConfig</span> <span class="token punctuation">{</span>
    <span class="token comment">/**
     * JWT配置
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">JwtProperties</span> jwtProperties<span class="token punctuation">;</span>
    <span class="token comment">/**
     * 忽略接口资源
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">IgnoreUrlsConfig</span> ignoreUrlsConfig<span class="token punctuation">;</span>
    <span class="token comment">/**
     * 当访问接口没有权限时，自定义的返回结果
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AdminUserAccessDeniedHandler</span> accessDeniedHandler<span class="token punctuation">;</span>
    <span class="token comment">/**
     * 当未登录或者token失效访问接口时，自定义的返回结果
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AdminUserAuthenticationEntryPoint</span> authenticationEntryPoint<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 静态资源
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> AUTH_STATIC_URLS <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">&quot;/&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/*.html&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/favicon.ico&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/*/*.html&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/*/*.css&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/*/*.js&quot;</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    <span class="token comment">/**
     * 接口资源
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> AUTH_API_URLS <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">&quot;/oauth/*&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/admin/login&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/admin/register&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;/admin/captcha/*&quot;</span><span class="token punctuation">,</span>
            <span class="token string">&quot;/interface/**&quot;</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
    
    <span class="token comment">/**
     * 于配置需要拦截的url路径、jwt过滤器及出异常后的处理器；
     */</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token class-name">SecurityFilterChain</span> <span class="token function">filterChain</span><span class="token punctuation">(</span><span class="token class-name">HttpSecurity</span> httpSecurity<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
      httpSecurity
              <span class="token comment">// 由于使用的是JWT，我们这里不需要csrf</span>
              <span class="token punctuation">.</span><span class="token function">csrf</span><span class="token punctuation">(</span><span class="token class-name">CsrfConfigurer</span><span class="token operator">::</span><span class="token function">disable</span><span class="token punctuation">)</span>
              <span class="token comment">// 基于token，所以不需要session</span>
              <span class="token punctuation">.</span><span class="token function">sessionManagement</span><span class="token punctuation">(</span>session <span class="token operator">-&gt;</span> session<span class="token punctuation">.</span><span class="token function">sessionCreationPolicy</span><span class="token punctuation">(</span><span class="token class-name">SessionCreationPolicy</span><span class="token punctuation">.</span>STATELESS<span class="token punctuation">)</span><span class="token punctuation">)</span>
              <span class="token punctuation">.</span><span class="token function">authorizeRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
              <span class="token comment">// 允许对于网站静态资源的无授权访问</span>
              <span class="token punctuation">.</span><span class="token function">requestMatchers</span><span class="token punctuation">(</span><span class="token class-name">HttpMethod</span><span class="token punctuation">.</span>GET<span class="token punctuation">,</span> AUTH_STATIC_URLS<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
              <span class="token comment">// 对登录注册要允许匿名访问</span>
              <span class="token punctuation">.</span><span class="token function">requestMatchers</span><span class="token punctuation">(</span>AUTH_API_URLS<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">requestMatchers</span><span class="token punctuation">(</span>ignoreUrlsConfig<span class="token punctuation">.</span><span class="token function">getIgnoreUrls</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
              <span class="token comment">// 跨域请求会先进行一次options请求</span>
              <span class="token punctuation">.</span><span class="token function">requestMatchers</span><span class="token punctuation">(</span><span class="token class-name">HttpMethod</span><span class="token punctuation">.</span>OPTIONS<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
              <span class="token comment">// 测试时全部运行访问</span>
              <span class="token comment">//.antMatchers(&quot;/**&quot;)</span>
              <span class="token comment">//.permitAll()</span>
              <span class="token comment">// 除上面外的所有请求全部需要鉴权认证</span>
              <span class="token punctuation">.</span><span class="token function">anyRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">authenticated</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
      <span class="token comment">// 禁用缓存</span>
      httpSecurity<span class="token punctuation">.</span><span class="token function">headers</span><span class="token punctuation">(</span>header <span class="token operator">-&gt;</span> header<span class="token punctuation">.</span><span class="token function">cacheControl</span><span class="token punctuation">(</span><span class="token class-name">HeadersConfigurer<span class="token punctuation">.</span>CacheControlConfig</span><span class="token operator">::</span><span class="token function">disable</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 添加JWT filter</span>
      httpSecurity<span class="token punctuation">.</span><span class="token function">addFilterBefore</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">JwtAuthTokenFilter</span><span class="token punctuation">(</span>jwtProperties<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">UsernamePasswordAuthenticationFilter</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">//添加自定义未授权和未登录结果返回</span>
      httpSecurity<span class="token punctuation">.</span><span class="token function">exceptionHandling</span><span class="token punctuation">(</span>exception <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>
        exception<span class="token punctuation">.</span><span class="token function">accessDeniedHandler</span><span class="token punctuation">(</span>accessDeniedHandler<span class="token punctuation">)</span><span class="token punctuation">;</span>
        exception<span class="token punctuation">.</span><span class="token function">authenticationEntryPoint</span><span class="token punctuation">(</span>authenticationEntryPoint<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  
      <span class="token keyword">return</span> httpSecurity<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">PasswordEncoder</span> <span class="token function">passwordEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BCryptPasswordEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br><span class="line-number">76</span><br><span class="line-number">77</span><br><span class="line-number">78</span><br><span class="line-number">79</span><br><span class="line-number">80</span><br></div></div><h3 id="springsecurity-过滤器"><a href="#springsecurity-过滤器" class="header-anchor">#</a> SpringSecurity 过滤器</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * JWT登录授权过滤器
 */</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JwtAuthTokenFilter</span> <span class="token keyword">extends</span> <span class="token class-name">OncePerRequestFilter</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">JwtProperties</span> jwtProperties<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">JwtAuthTokenFilter</span><span class="token punctuation">(</span><span class="token class-name">JwtProperties</span> jwtProperties<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>jwtProperties <span class="token operator">=</span> jwtProperties<span class="token punctuation">;</span>
        <span class="token class-name">String</span> accessTokenHeader <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getAccessTokenHeader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> chain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
        <span class="token class-name">String</span> accessTokenHeader <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getAccessTokenHeader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> refreshTokenHeader <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getRefreshTokenHeader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> tokenHead <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getTokenHead</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">String</span> secret <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getSecret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Long</span> expiration <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getExpiration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Long</span> advance <span class="token operator">=</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getAdvance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">String</span> authHeader <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getHeader</span><span class="token punctuation">(</span>accessTokenHeader<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span>authHeader<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> authHeader<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span>tokenHead<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// The part after &quot;Bearer &quot; 有个空格</span>
            <span class="token class-name">String</span> authToken <span class="token operator">=</span> authHeader<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>tokenHead<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AdminUser</span><span class="token punctuation">&gt;</span></span> jwtPayload <span class="token operator">=</span> <span class="token class-name">JwtUtils</span><span class="token punctuation">.</span><span class="token function">getUserInfoFromToken</span><span class="token punctuation">(</span>authToken<span class="token punctuation">,</span> secret<span class="token punctuation">,</span> <span class="token class-name">AdminUser</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">AdminUser</span> adminUser <span class="token operator">=</span> jwtPayload<span class="token punctuation">.</span><span class="token function">getUserInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            log<span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token string">&quot;checking user:{}&quot;</span><span class="token punctuation">,</span> adminUser<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>adminUser<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token class-name">SecurityContextHolder</span><span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAuthentication</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment">// 验证JWT Token的正确性和是否失效</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">JwtUtils</span><span class="token punctuation">.</span><span class="token function">validateTokenExpire</span><span class="token punctuation">(</span>authToken<span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">// 验证能否刷新JWT Token，放入http返回头中</span>
                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">JwtUtils</span><span class="token punctuation">.</span><span class="token function">canRefreshTokenExpire</span><span class="token punctuation">(</span>authToken<span class="token punctuation">,</span> secret<span class="token punctuation">,</span> advance<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                        response<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span>refreshTokenHeader<span class="token punctuation">,</span> tokenHead <span class="token operator">+</span> <span class="token class-name">JwtUtils</span><span class="token punctuation">.</span><span class="token function">refreshTokenExpire</span><span class="token punctuation">(</span>authToken<span class="token punctuation">,</span> adminUser<span class="token punctuation">,</span> secret<span class="token punctuation">,</span> expiration<span class="token punctuation">,</span> advance<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                    <span class="token punctuation">}</span>
                    <span class="token comment">// 验证JWT Token通过，要放入SpringSecurity中</span>
                    <span class="token class-name">SpringSecurityUtil</span><span class="token punctuation">.</span><span class="token function">setCurrentUser</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> adminUser<span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        chain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br></div></div><h3 id="springsecurity-异常处理自定义类"><a href="#springsecurity-异常处理自定义类" class="header-anchor">#</a> SpringSecurity 异常处理自定义类</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * 当访问接口没有权限时，自定义的返回结果
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AdminUserAccessDeniedHandler</span> <span class="token keyword">implements</span> <span class="token class-name">AccessDeniedHandler</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">handle</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">AccessDeniedException</span> e<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
        response<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">&quot;UTF-8&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">&quot;application/json&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">setStatus</span><span class="token punctuation">(</span><span class="token class-name">HttpStatus</span><span class="token punctuation">.</span>FORBIDDEN<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">JSONUtil</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token class-name">R</span><span class="token punctuation">.</span><span class="token function">forbidden</span><span class="token punctuation">(</span><span class="token string">&quot;访问权限受限或已过期&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * 当未登录或者token失效访问接口时，自定义的返回结果
 */</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AdminUserAuthenticationEntryPoint</span> <span class="token keyword">implements</span> <span class="token class-name">AuthenticationEntryPoint</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">commence</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">AuthenticationException</span> authException<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
        response<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">&quot;UTF-8&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">&quot;application/json&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">setStatus</span><span class="token punctuation">(</span><span class="token class-name">HttpStatus</span><span class="token punctuation">.</span>UNAUTHORIZED<span class="token punctuation">.</span><span class="token function">value</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">JSONUtil</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token class-name">R</span><span class="token punctuation">.</span><span class="token function">unauthorized</span><span class="token punctuation">(</span><span class="token string">&quot;未登录或Token失效&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><h3 id="springsecurity-使用工具类"><a href="#springsecurity-使用工具类" class="header-anchor">#</a> SpringSecurity 使用工具类</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * 获取当前登录用户
 */</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SpringSecurityUtil</span> <span class="token punctuation">{</span>
    <span class="token comment">/**
     * 获取当前登录用户
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getCurrentUserName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">getCurrentUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取当前登录用户ID
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getCurrentUserId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">getCurrentUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取当登录用户所属系统ID
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getCurrentSystemId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">getCurrentUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getSystemId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 获取当前登录用户信息
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">AdminUser</span> <span class="token function">getCurrentUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">SecurityContext</span> securityContext <span class="token operator">=</span> <span class="token class-name">SecurityContextHolder</span><span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">UsernamePasswordAuthenticationToken</span> authentication <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">UsernamePasswordAuthenticationToken</span><span class="token punctuation">)</span> securityContext<span class="token punctuation">.</span><span class="token function">getAuthentication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">AdminUser</span> umsUserVO <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">AdminUser</span><span class="token punctuation">)</span> authentication<span class="token punctuation">.</span><span class="token function">getPrincipal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>umsUserVO<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">return</span> umsUserVO<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ForbiddenException</span><span class="token punctuation">(</span><span class="token string">&quot;访问权限受限或已过期(403)&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 设置当前登录用户信息
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">setCurrentUser</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">AdminUser</span> adminUser<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">SimpleGrantedAuthority</span><span class="token punctuation">&gt;</span></span> authorities <span class="token operator">=</span>
                    adminUser<span class="token punctuation">.</span><span class="token function">getRoleIds</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>roleId <span class="token operator">-&gt;</span> <span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span>roleId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>roleId <span class="token operator">-&gt;</span> <span class="token keyword">new</span> <span class="token class-name">SimpleGrantedAuthority</span><span class="token punctuation">(</span>roleId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token class-name">Collectors</span><span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">UsernamePasswordAuthenticationToken</span> authentication <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UsernamePasswordAuthenticationToken</span><span class="token punctuation">(</span>adminUser<span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">,</span> authorities<span class="token punctuation">)</span><span class="token punctuation">;</span>
            authentication<span class="token punctuation">.</span><span class="token function">setDetails</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">WebAuthenticationDetailsSource</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">buildDetails</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">SecurityContextHolder</span><span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setAuthentication</span><span class="token punctuation">(</span>authentication<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ForbiddenException</span><span class="token punctuation">(</span><span class="token string">&quot;访问权限受限或已过期(403)&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br></div></div><h2 id="jwt"><a href="#jwt" class="header-anchor">#</a> JWT</h2> <ul><li>JWT是JSON WEB TOKEN的缩写，它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象，由于使用了数字签名，所以是可信任和安全的。</li></ul> <h3 id="jwt的组成"><a href="#jwt的组成" class="header-anchor">#</a> JWT的组成</h3> <ul><li>JWT token的格式：header.payload.signature</li></ul> <h4 id="header中用于存放签名的生成算法"><a href="#header中用于存放签名的生成算法" class="header-anchor">#</a> header中用于存放签名的生成算法</h4> <div class="language-json line-numbers-mode"><pre class="language-json"><code><span class="token punctuation">{</span><span class="token property">&quot;alg&quot;</span><span class="token operator">:</span> <span class="token string">&quot;HS512&quot;</span><span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h4 id="payload中用于存放用户名、token的生成时间和过期时间"><a href="#payload中用于存放用户名、token的生成时间和过期时间" class="header-anchor">#</a> payload中用于存放用户名、token的生成时间和过期时间</h4> <div class="language-json line-numbers-mode"><pre class="language-json"><code><span class="token punctuation">{</span><span class="token property">&quot;sub&quot;</span><span class="token operator">:</span><span class="token string">&quot;admin&quot;</span><span class="token punctuation">,</span><span class="token property">&quot;created&quot;</span><span class="token operator">:</span><span class="token number">1489079981393</span><span class="token punctuation">,</span><span class="token property">&quot;exp&quot;</span><span class="token operator">:</span><span class="token number">1489684781</span><span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h4 id="signature为以header和payload生成的签名-一旦header和payload被篡改-验证将失败"><a href="#signature为以header和payload生成的签名-一旦header和payload被篡改-验证将失败" class="header-anchor">#</a> signature为以header和payload生成的签名，一旦header和payload被篡改，验证将失败</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">String</span> signature <span class="token operator">=</span> <span class="token function">HMACSHA512</span><span class="token punctuation">(</span><span class="token function">base64UrlEncode</span><span class="token punctuation">(</span>header<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;.&quot;</span> <span class="token operator">+</span> <span class="token function">base64UrlEncode</span><span class="token punctuation">(</span>payload<span class="token punctuation">)</span><span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><div class="custom-block tip"><p class="custom-block-title">提示</p> <p>可以在JWT网站解析JWT token，地址：<a href="https://jwt.io/" target="_blank" rel="noopener noreferrer">JWT<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></p></div> <p><img src="/turbo-cloud-blog/assets/img/jwt-signature-verified.png" alt="jwt-signature-verified"></p> <h3 id="jwt-使用"><a href="#jwt-使用" class="header-anchor">#</a> JWT 使用</h3> <ul><li>生成<code>JWT Token</code>返回给Vue前端，Vue前端发起请求需要再http请求（Request）header的<code>Authorization</code>里面携带<code>JWT Token</code>回来；<code>JWT Token</code>存在有效期验证，有效期内发送的请求临过期Token验证通过，<code>JWT Token</code>会重新生成，放回http返回（Response）header的<code>Refresh-Authorization</code>里面。</li></ul> <h3 id="jwt-配置类"><a href="#jwt-配置类" class="header-anchor">#</a> JWT 配置类</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * Jwt配置类
 */</span>
<span class="token annotation punctuation">@Data</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token annotation punctuation">@ConfigurationProperties</span><span class="token punctuation">(</span>prefix <span class="token operator">=</span> <span class="token string">&quot;jwt&quot;</span><span class="token punctuation">,</span> ignoreInvalidFields <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JwtProperties</span> <span class="token punctuation">{</span>
    <span class="token comment">/**
     * JWT存储的请求头（验证）
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> accessTokenHeader<span class="token punctuation">;</span>
    <span class="token comment">/**
     * JWT存储的请求头（刷新）
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> refreshTokenHeader<span class="token punctuation">;</span>
    <span class="token comment">/**
     * JWT负载中拿到开头
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> tokenHead<span class="token punctuation">;</span>
    <span class="token comment">/**
     * JWT加解密使用的密钥
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> secret<span class="token punctuation">;</span>
    <span class="token comment">/**
     * JWT的超期限时间(秒)
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">Long</span> expiration<span class="token punctuation">;</span>
    <span class="token comment">/**
     * JWT的预先时间(秒)
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">Long</span> advance<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br></div></div><h3 id="jwt-工具类"><a href="#jwt-工具类" class="header-anchor">#</a> JWT 工具类</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * 生成token以及校验token相关方法
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JwtUtils</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> JWT_PAYLOAD_USER_KEY <span class="token operator">=</span> <span class="token string">&quot;user&quot;</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Long</span> FORMAT_TIME_MS <span class="token operator">=</span> <span class="token number">1000L</span><span class="token punctuation">;</span>
  
    <span class="token comment">/**
     * 生成token
     *
     * @param userInfo   载荷中的数据
     * @param secret     秘钥
     * @param expiration 失效时间
     * @return JWT
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">generateTokenExpire</span><span class="token punctuation">(</span><span class="token class-name">Object</span> userInfo<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">,</span> <span class="token keyword">long</span> expiration<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token class-name">Jwts</span><span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">claim</span><span class="token punctuation">(</span>JWT_PAYLOAD_USER_KEY<span class="token punctuation">,</span> <span class="token class-name">JSONUtil</span><span class="token punctuation">.</span><span class="token function">toJsonStr</span><span class="token punctuation">(</span>userInfo<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span><span class="token function">createJTI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setExpiration</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> expiration <span class="token operator">*</span> FORMAT_TIME_MS<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">signWith</span><span class="token punctuation">(</span><span class="token class-name">SignatureAlgorithm</span><span class="token punctuation">.</span>HS512<span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">compact</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 验证token
     *
     * @param token  用户请求中的token
     * @param secret 秘钥
     * @return 是否有效
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">validateTokenExpire</span><span class="token punctuation">(</span><span class="token class-name">String</span> token<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">Claims</span> body <span class="token operator">=</span> <span class="token function">parserToken</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">isNull</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token class-name">Date</span> expiredDate <span class="token operator">=</span> body<span class="token punctuation">.</span><span class="token function">getExpiration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token comment">// 过期时间应该在当前时间之后视为有效</span>
      <span class="token keyword">boolean</span> isExpire <span class="token operator">=</span> expiredDate<span class="token punctuation">.</span><span class="token function">after</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> isExpire<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 验证token
     *
     * @param userInfo   载荷中的数据
     * @param secret     秘钥
     * @param expiration 失效秒（s）
     * @param advance    预先秒（s）
     * @return 是否有效
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">refreshTokenExpire</span><span class="token punctuation">(</span><span class="token class-name">String</span> token<span class="token punctuation">,</span> <span class="token class-name">Object</span> userInfo<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">,</span> <span class="token keyword">long</span> expiration<span class="token punctuation">,</span> <span class="token keyword">long</span> advance<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">canRefreshTokenExpire</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> secret<span class="token punctuation">,</span> advance<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token function">generateTokenExpire</span><span class="token punctuation">(</span>userInfo<span class="token punctuation">,</span> secret<span class="token punctuation">,</span> expiration<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> token<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 是否能刷新token
     *
     * @param secret  秘钥
     * @param advance 预先秒（s）
     * @return 是否有效
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">canRefreshTokenExpire</span><span class="token punctuation">(</span><span class="token class-name">String</span> token<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">,</span> <span class="token keyword">long</span> advance<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">Claims</span> body <span class="token operator">=</span> <span class="token function">parserToken</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">isNull</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token class-name">Long</span> expiredDateMs <span class="token operator">=</span> body<span class="token punctuation">.</span><span class="token function">getExpiration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token class-name">Long</span> nowDateMs <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> expiredDateMs <span class="token operator">&lt;</span> <span class="token punctuation">(</span>nowDateMs <span class="token operator">+</span> advance <span class="token operator">*</span> FORMAT_TIME_MS<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 解析token
     *
     * @param token  用户请求中的token
     * @param secret 秘钥
     * @return Jws&lt;Claims&gt;
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">Claims</span> <span class="token function">parserToken</span><span class="token punctuation">(</span><span class="token class-name">String</span> token<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">Claims</span> claims<span class="token punctuation">;</span>
      <span class="token keyword">try</span> <span class="token punctuation">{</span>
        claims <span class="token operator">=</span> <span class="token class-name">Jwts</span><span class="token punctuation">.</span><span class="token function">parser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setSigningKey</span><span class="token punctuation">(</span>secret<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parseClaimsJws</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">ExpiredJwtException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        claims <span class="token operator">=</span> e<span class="token punctuation">.</span><span class="token function">getClaims</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> claims<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 生成JWT ID
     */</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">createJTI</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token class-name">Base64</span><span class="token punctuation">.</span><span class="token function">getEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>UUID<span class="token punctuation">.</span><span class="token function">randomUUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param secret    秘钥
     * @param userClass 用户实体类
     * @return 用户信息
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">getUserInfoFromToken</span><span class="token punctuation">(</span><span class="token class-name">String</span> token<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> userClass<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">Claims</span> body <span class="token operator">=</span> <span class="token function">parserToken</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> claims <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      claims<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>body<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token class-name">String</span> userInfoJson <span class="token operator">=</span> body<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>JWT_PAYLOAD_USER_KEY<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      claims<span class="token punctuation">.</span><span class="token function">setUserInfo</span><span class="token punctuation">(</span><span class="token class-name">JSONUtil</span><span class="token punctuation">.</span><span class="token function">toBean</span><span class="token punctuation">(</span>userInfoJson<span class="token punctuation">,</span> userClass<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      claims<span class="token punctuation">.</span><span class="token function">setExpiration</span><span class="token punctuation">(</span>body<span class="token punctuation">.</span><span class="token function">getExpiration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> claims<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  
    <span class="token comment">/**
     * 获取token中的载荷信息
     *
     * @param token  用户请求中的令牌
     * @param secret 秘钥
     * @return 用户信息
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">getUserInfoFromToken</span><span class="token punctuation">(</span><span class="token class-name">String</span> token<span class="token punctuation">,</span> <span class="token class-name">String</span> secret<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token class-name">Claims</span> body <span class="token operator">=</span> <span class="token function">parserToken</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> secret<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> claims <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JwtPayload</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      claims<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>body<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      claims<span class="token punctuation">.</span><span class="token function">setExpiration</span><span class="token punctuation">(</span>body<span class="token punctuation">.</span><span class="token function">getExpiration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword">return</span> claims<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br><span class="line-number">76</span><br><span class="line-number">77</span><br><span class="line-number">78</span><br><span class="line-number">79</span><br><span class="line-number">80</span><br><span class="line-number">81</span><br><span class="line-number">82</span><br><span class="line-number">83</span><br><span class="line-number">84</span><br><span class="line-number">85</span><br><span class="line-number">86</span><br><span class="line-number">87</span><br><span class="line-number">88</span><br><span class="line-number">89</span><br><span class="line-number">90</span><br><span class="line-number">91</span><br><span class="line-number">92</span><br><span class="line-number">93</span><br><span class="line-number">94</span><br><span class="line-number">95</span><br><span class="line-number">96</span><br><span class="line-number">97</span><br><span class="line-number">98</span><br><span class="line-number">99</span><br><span class="line-number">100</span><br><span class="line-number">101</span><br><span class="line-number">102</span><br><span class="line-number">103</span><br><span class="line-number">104</span><br><span class="line-number">105</span><br><span class="line-number">106</span><br><span class="line-number">107</span><br><span class="line-number">108</span><br><span class="line-number">109</span><br><span class="line-number">110</span><br><span class="line-number">111</span><br><span class="line-number">112</span><br><span class="line-number">113</span><br><span class="line-number">114</span><br><span class="line-number">115</span><br><span class="line-number">116</span><br><span class="line-number">117</span><br><span class="line-number">118</span><br><span class="line-number">119</span><br><span class="line-number">120</span><br><span class="line-number">121</span><br><span class="line-number">122</span><br><span class="line-number">123</span><br><span class="line-number">124</span><br><span class="line-number">125</span><br><span class="line-number">126</span><br><span class="line-number">127</span><br><span class="line-number">128</span><br></div></div><h2 id="happy-captcha-图形验证码"><a href="#happy-captcha-图形验证码" class="header-anchor">#</a> Happy Captcha 图形验证码</h2> <ul><li>连续3次输入错误的登录密码，会触发登录保护机制需要输入图形验证码。</li></ul> <p><img src="/turbo-cloud-blog/assets/img/login-happy-captcha-verified.png" alt="login-happy-captcha-verified"></p> <blockquote><p>HappyCaptcha一共提供了12种验证码类型，你可以自由选择其中的一种类型作为验证码的内容形式。默认情况下，验证码使用数字和大小写字母的混合形式。验证码类型值由CaptchaType类提供，内容如下表：</p></blockquote> <table><thead><tr><th>值</th> <th>说明</th></tr></thead> <tbody><tr><td>DEFAULT</td> <td>数字、大小写字母随机组合</td></tr> <tr><td>ARITHMETIC</td> <td>加、减、乘算数运算表达式</td></tr> <tr><td>ARITHMETIC_ZH</td> <td>中文简体加、减、乘算数运算表达式描述</td></tr> <tr><td>CHINESE</td> <td>常见汉字（3500个）随机组合</td></tr> <tr><td>NUMBER</td> <td>0~9数字随机组合</td></tr> <tr><td>NUMBER_ZH_CN</td> <td>中文数字（零至九）随机组合</td></tr> <tr><td>NUMBER_ZH_HK</td> <td>中文繁体数字（零至玖）随机组合</td></tr> <tr><td>WORD</td> <td>大小写字母随机组合</td></tr> <tr><td>WORD_LOWER</td> <td>小写字母随机组合</td></tr> <tr><td>WORD_UPPER</td> <td>大写字母随机组合</td></tr> <tr><td>WORD_NUMBER_LOWER</td> <td>数字、小写字母随机组合</td></tr> <tr><td>WORD_NUMBER_UPPER</td> <td>数字、大写字母随机组合</td></tr></tbody></table> <div class="custom-block tip"><p class="custom-block-title">提示</p> <p>请参考开源项目文档，地址：<a href="https://toscode.gitee.com/zyjhs/Happy-Captcha/" target="_blank" rel="noopener noreferrer">Happy-Captcha<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>，
此项目好久没有更新了，Spring Boot 3+ 已将所有底层依赖项从 Java EE 迁移到了 Jakarta EE API，原项目不支持Spring Boot 3+，下载源码进行了修改，但是使用起来确实Happy。</p></div> <h3 id="图形验证码接口"><a href="#图形验证码接口" class="header-anchor">#</a> 图形验证码接口</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * 图形验证码 前端控制器
 */</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@RequiredArgsConstructor</span>
<span class="token annotation punctuation">@RestController</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HappyCaptchaController</span> <span class="token punctuation">{</span>
    
    <span class="token comment">/**
     * 生成图形验证码
     * &lt;p&gt;
     * 值	说明
     * DEFAULT	            数字、大小写字母随机组合
     * ARITHMETIC	        加、减、乘算数运算表达式
     * ARITHMETIC_ZH        中文简体加、减、乘算数运算表达式描述
     * CHINESE	            常见汉字（3500个）随机组合
     * NUMBER	            0~9数字随机组合
     * NUMBER_ZH_CN	        中文数字（零至九）随机组合
     * NUMBER_ZH_HK	        中文繁体数字（零至玖）随机组合
     * WORD	                大小写字母随机组合
     * WORD_LOWER	        小写字母随机组合
     * WORD_UPPER	        大写字母随机组合
     * WORD_NUMBER_LOWER	数字、小写字母随机组合
     * WORD_NUMBER_UPPER	数字、大写字母随机组合
     * &lt;p&gt;
     * HappyCaptcha.require(request,response).type(CaptchaType.CHINESE).build().finish();
     * &lt;p&gt;
     * 可供选择的值有IMG和ANIM
     * HappyCaptcha.require(request,response).style(CaptchaStyle.ANIM).build().finish();
     * &lt;p&gt;
     * &lt;a href=&quot;https://gitee.com/ramostear/Happy-Captcha/blob/master/README.md&quot;&gt;...&lt;/a&gt;
     */</span>
    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/admin/captcha/getCaptchaImage&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">getCaptchaImage</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">HappyCaptcha</span><span class="token punctuation">.</span><span class="token function">require</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">type</span><span class="token punctuation">(</span><span class="token class-name">CaptchaType</span><span class="token punctuation">.</span>ARITHMETIC<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">finish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 是否显示图像验证码
     */</span>
    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/admin/captcha/showCaptchaImage&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">Result</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Boolean</span><span class="token punctuation">&gt;</span></span> <span class="token function">displayCaptchaImage</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Boolean</span> isShow <span class="token operator">=</span> <span class="token class-name">HappyCaptchaRequestUtil</span><span class="token punctuation">.</span><span class="token function">showHappyCaptcha</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token class-name">R</span><span class="token punctuation">.</span><span class="token function">result</span><span class="token punctuation">(</span>isShow<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br></div></div><h3 id="用户登录验证"><a href="#用户登录验证" class="header-anchor">#</a> 用户登录验证</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">/**
 * 用户 逻辑处理类
 */</span>
<span class="token annotation punctuation">@Slf4j</span>
<span class="token annotation punctuation">@RequiredArgsConstructor</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserLogic</span> <span class="token punctuation">{</span>

    <span class="token keyword">final</span> <span class="token class-name">JwtProperties</span> jwtProperties<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">IUmsUserService</span> umsUserService<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">IUmsRoleService</span> umsRoleService<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">IUmsUserRoleRelationService</span> umsUserRoleRelationService<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">IUmsDeptService</span> umsDeptService<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">IUmsUserDeptRelationService</span> umsUserDeptRelationService<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">IUmsHomeRoleService</span> umsHomeRoleService<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">PasswordEncoder</span> passwordEncoder<span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token class-name">MinioFileClient</span> minioFileClient<span class="token punctuation">;</span>

    <span class="token comment">/**
     * 根据用户ID，查询用户信息
     * @param userId 用户ID
     * @return 用户实体
     */</span>
    <span class="token keyword">private</span> <span class="token class-name">UmsUserVO</span> <span class="token function">loadUserByUserId</span><span class="token punctuation">(</span><span class="token class-name">String</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">UmsUser</span> umsUser <span class="token operator">=</span> umsUserService<span class="token punctuation">.</span><span class="token function">getById</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">isNull</span><span class="token punctuation">(</span>umsUser<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token class-name">UmsUserVO</span> umsUserVO <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UmsUserVO</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">BeanUtils</span><span class="token punctuation">.</span><span class="token function">copyProperties</span><span class="token punctuation">(</span>umsUser<span class="token punctuation">,</span> umsUserVO<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token class-name">LambdaQueryWrapper</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UmsUserRoleRelation</span><span class="token punctuation">&gt;</span></span> userRoleRelationLambdaQueryWrapper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LambdaQueryWrapper</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            userRoleRelationLambdaQueryWrapper<span class="token punctuation">.</span><span class="token function">eq</span><span class="token punctuation">(</span><span class="token class-name">UmsUserRoleRelation</span><span class="token operator">::</span><span class="token function">getUserId</span><span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UmsUserRoleRelation</span><span class="token punctuation">&gt;</span></span> userRoleRelationList <span class="token operator">=</span> umsUserRoleRelationService<span class="token punctuation">.</span><span class="token function">list</span><span class="token punctuation">(</span>userRoleRelationLambdaQueryWrapper<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>userRoleRelationList<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>userRoleRelationList<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> roleIdList <span class="token operator">=</span>
                        userRoleRelationList<span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">UmsUserRoleRelation</span><span class="token operator">::</span><span class="token function">getRoleId</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>roleId <span class="token operator">-&gt;</span> <span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span>roleId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                umsUserVO<span class="token punctuation">.</span><span class="token function">setRoleIds</span><span class="token punctuation">(</span>roleIdList<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token class-name">LambdaQueryWrapper</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UmsUserDeptRelation</span><span class="token punctuation">&gt;</span></span> userDeptRelationLambdaQueryWrapper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LambdaQueryWrapper</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            userDeptRelationLambdaQueryWrapper<span class="token punctuation">.</span><span class="token function">eq</span><span class="token punctuation">(</span><span class="token class-name">UmsUserDeptRelation</span><span class="token operator">::</span><span class="token function">getUserId</span><span class="token punctuation">,</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">UmsUserDeptRelation</span><span class="token punctuation">&gt;</span></span> umsUserDeptRelationList <span class="token operator">=</span> umsUserDeptRelationService<span class="token punctuation">.</span><span class="token function">list</span><span class="token punctuation">(</span>userDeptRelationLambdaQueryWrapper<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>umsUserDeptRelationList<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>umsUserDeptRelationList<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> deptIdList <span class="token operator">=</span>
                        umsUserDeptRelationList<span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">UmsUserDeptRelation</span><span class="token operator">::</span><span class="token function">getDeptId</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span>deptId <span class="token operator">-&gt;</span> <span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span>deptId<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                umsUserVO<span class="token punctuation">.</span><span class="token function">setDeptIds</span><span class="token punctuation">(</span>deptIdList<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token keyword">return</span> umsUserVO<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 用户登录
     *
     * @param umsUserQO 用户登录实体
     * @param request   请求体
     * @return UmsUserTokenVO
     */</span>
    <span class="token keyword">public</span> <span class="token class-name">UmsUserTokenVO</span> <span class="token function">login</span><span class="token punctuation">(</span><span class="token class-name">UmsUserQO</span> umsUserQO<span class="token punctuation">,</span> <span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isBlank</span><span class="token punctuation">(</span>umsUserQO<span class="token punctuation">.</span><span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BusinessException</span><span class="token punctuation">(</span><span class="token string">&quot;用户名不能为空&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isBlank</span><span class="token punctuation">(</span>umsUserQO<span class="token punctuation">.</span><span class="token function">getPassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BusinessException</span><span class="token punctuation">(</span><span class="token string">&quot;密码不能为空&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token class-name">String</span> userId <span class="token operator">=</span> umsUserQO<span class="token punctuation">.</span><span class="token function">getSystemId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token class-name">UMSConstants</span><span class="token punctuation">.</span>STR_SEPARATOR_UNDERLINE <span class="token operator">+</span> umsUserQO<span class="token punctuation">.</span><span class="token function">getUsername</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token keyword">boolean</span> isCheckHappyCaptcha <span class="token operator">=</span> <span class="token class-name">HappyCaptchaRequestUtil</span><span class="token punctuation">.</span><span class="token function">showHappyCaptcha</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>isCheckHappyCaptcha <span class="token operator">||</span> <span class="token class-name">StrUtil</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span>umsUserQO<span class="token punctuation">.</span><span class="token function">getVerifyCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">boolean</span> flag <span class="token operator">=</span> <span class="token class-name">HappyCaptcha</span><span class="token punctuation">.</span><span class="token function">verification</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> umsUserQO<span class="token punctuation">.</span><span class="token function">getVerifyCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>flag<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BusinessException</span><span class="token punctuation">(</span><span class="token string">&quot;验证码不正确&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
                <span class="token class-name">HappyCaptcha</span><span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token comment">/*
         * 根据用户名查询用户信息
         */</span>
        <span class="token class-name">UmsUserVO</span> umsUserVO <span class="token operator">=</span> <span class="token function">loadUserByUserId</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">/*
         * 比对密码正确性
         */</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>passwordEncoder<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span>umsUserQO<span class="token punctuation">.</span><span class="token function">getPassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> umsUserVO<span class="token punctuation">.</span><span class="token function">getPassword</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">int</span> loginFailCount <span class="token operator">=</span> <span class="token class-name">HappyCaptchaRequestUtil</span><span class="token punctuation">.</span><span class="token function">getLoginFailCount</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token class-name">HappyCaptchaRequestUtil</span><span class="token punctuation">.</span><span class="token function">setLoginFailCount</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BusinessException</span><span class="token punctuation">(</span><span class="token string">&quot;用户名或密码不正确（&quot;</span> <span class="token operator">+</span> <span class="token punctuation">(</span>loginFailCount <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;次）&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment">/*
         * 生成JWTToken
         */</span>
        <span class="token class-name">UmsUserTokenVO</span> umsUserTokenVO <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UmsUserTokenVO</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        umsUserTokenVO<span class="token punctuation">.</span><span class="token function">setAccessToken</span><span class="token punctuation">(</span>jwtProperties<span class="token punctuation">.</span><span class="token function">getTokenHead</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token class-name">JwtUtils</span><span class="token punctuation">.</span><span class="token function">generateTokenExpire</span><span class="token punctuation">(</span>umsUserVO<span class="token punctuation">,</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getSecret</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> jwtProperties<span class="token punctuation">.</span><span class="token function">getExpiration</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">HappyCaptchaRequestUtil</span><span class="token punctuation">.</span><span class="token function">removeLoginFailCount</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> umsUserTokenVO<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">/**
     * 用户登出
     */</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">logout</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SecurityContextHolder</span><span class="token punctuation">.</span><span class="token function">clearContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br><span class="line-number">76</span><br><span class="line-number">77</span><br><span class="line-number">78</span><br><span class="line-number">79</span><br><span class="line-number">80</span><br><span class="line-number">81</span><br><span class="line-number">82</span><br><span class="line-number">83</span><br><span class="line-number">84</span><br><span class="line-number">85</span><br><span class="line-number">86</span><br><span class="line-number">87</span><br><span class="line-number">88</span><br><span class="line-number">89</span><br><span class="line-number">90</span><br><span class="line-number">91</span><br><span class="line-number">92</span><br><span class="line-number">93</span><br><span class="line-number">94</span><br><span class="line-number">95</span><br><span class="line-number">96</span><br><span class="line-number">97</span><br><span class="line-number">98</span><br><span class="line-number">99</span><br><span class="line-number">100</span><br><span class="line-number">101</span><br><span class="line-number">102</span><br><span class="line-number">103</span><br><span class="line-number">104</span><br><span class="line-number">105</span><br><span class="line-number">106</span><br><span class="line-number">107</span><br><span class="line-number">108</span><br><span class="line-number">109</span><br><span class="line-number">110</span><br><span class="line-number">111</span><br></div></div></div></div>  <div class="page-edit"><!----> <!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2023/05/30, 16:03:14</span></div></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/turbo-cloud-blog/pages/226c21/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">快速开始</div></a> <a href="/turbo-cloud-blog/pages/3b5af0/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">系统权限</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/turbo-cloud-blog/pages/226c21/" class="prev">快速开始</a></span> <span class="next"><a href="/turbo-cloud-blog/pages/3b5af0/">系统权限</a>→
      </span></p></div></div></div> <!----></main></div> <div class="footer"><div class="icons"><a href="https://gitee.com/aquarian-bottle" title="GitHub" target="_blank" class="iconfont icon-github"></a><a href="https://gitee.com/aquarian-bottle" title="Gitee" target="_blank" class="iconfont icon-gitee"></a><a href="864314760@qq.com" title="发邮件" target="_blank" class="iconfont icon-youjian"></a></div> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2016-2023
    <span><a href="https://gitee.com/aquarian-bottle" target="_blank" style="font-weight:bold">Team Aquarius</a> | Sponsored by <a href="https://www.jetbrains.com" target="_blank" style="font-weight:bold">JetBrains</a> | <a href="https://gitee.com/aquarian-bottle/" target=_blank>粤ICP备12009483号</a><p>友情链接：<a href="https://www.baomidou.com/" target="_blank" style="font-weight:bold">MybatisPlus</a> | <a href="https://www.macrozheng.com/" target="_blank" style="font-weight:bold">MacroZheng</a> | <a href="https://doc.vvbin.cn/" target="_blank" style="font-weight:bold">VbenAdmin</a> | <a href="https://www.antdv.com/" target="_blank" style="font-weight:bold">AntDesignVue</a></p></span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <div class="custom-html-window custom-html-window-rb" style="display:;"><div class="custom-wrapper"><span class="close-but">×</span> <div>
    <ins class="adsbygoogle"
    style="display:block"
    data-ad-client="ca-pub-4147143076931995"
    data-ad-slot="1866407052"
    data-ad-format="auto"
    data-full-width-responsive="true"></ins>
    <script>
        (adsbygoogle = window.adsbygoogle || []).push({});
    </script>
  </div></div></div></div><div class="global-ui"></div></div>
    <script src="/turbo-cloud-blog/assets/js/app.fa1a75e5.js" defer></script><script src="/turbo-cloud-blog/assets/js/2.5e61b679.js" defer></script><script src="/turbo-cloud-blog/assets/js/8.a23eef87.js" defer></script>
  </body>
</html>
